package com.boodaba.todocarts.test.app;

import static com.googlecode.instinct.expect.Expect.expect;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.jmock.Expectations;
import org.junit.runner.RunWith;

import com.boodaba.todocarts.app.ITodoSettingsActivity;
import com.boodaba.todocarts.app.TodoSettingsPresenter;
import com.boodaba.todocarts.domain.ILabelRepository;
import com.boodaba.todocarts.domain.Label;
import com.googlecode.instinct.integrate.junit4.InstinctRunner;
import com.googlecode.instinct.marker.annotate.BeforeSpecification;
import com.googlecode.instinct.marker.annotate.Mock;
import com.googlecode.instinct.marker.annotate.Specification;
import com.googlecode.instinct.marker.annotate.Subject;

@RunWith(InstinctRunner.class)
public class TodoSettingsPresenterSpecs {
	@Subject private TodoSettingsPresenter SUT;
	
	@Mock ITodoSettingsActivity todoSettingsActivity;
	@Mock ILabelRepository labelRepository;
	
	private Label trgLabel;
	
	private final String trgLabelTitle = "Label target";
	private final String todo1Title = "toDo one";
	private final String todo2Title = "Too twO";
	private final String todo3Title = "ttt Three one";
	
	
	@BeforeSpecification
	public void setUp() {
		SUT = new TodoSettingsPresenter(labelRepository);
		trgLabel = new Label(trgLabelTitle);
		expect.that(new Expectations() {{
			allowing(todoSettingsActivity).getTargetLabelTitle();
				will(returnValue(trgLabelTitle));
			allowing(labelRepository).getLabelByTitle(with(equal(trgLabelTitle)));
				will(returnValue(trgLabel));
		}});
	}
	
	@Specification
	void shouldSetTitleAndListOnInit() {
		expect.that(new Expectations() {{ 
			oneOf(todoSettingsActivity).setWorkingTitle(with(equal(trgLabelTitle)));
			oneOf(todoSettingsActivity).setWorkingList(with(equal(Collections.<String, Boolean>emptyMap())));
		}});
		SUT.initializeWith(todoSettingsActivity);
	}
	
	@Specification
	void shouldSetInitListByTodosTitles() {
		trgLabel.inviteTodo(todo1Title);
		trgLabel.inviteTodo(todo2Title);
		expect.that(new Expectations() {{
			Map<String, Boolean> chkMap = new HashMap<String, Boolean>();
			chkMap.put(todo1Title, false);
			chkMap.put(todo2Title, false);
			oneOf(todoSettingsActivity).setWorkingTitle(with(equal(trgLabelTitle)));
			oneOf(todoSettingsActivity).setWorkingList(with(equal(chkMap)));
		}});
		SUT.initializeWith(todoSettingsActivity);
	}
	
	@Specification
	void shouldAddNewTodoToLabelAndToListAndSaveIt() {
		setInited();
		setNullSelected();
		expect.that(trgLabel.getTodoByTitle(todo3Title) == null);
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue(todo3Title));
			oneOf(todoSettingsActivity).addToWorkingList(with(equal(todo3Title)));
			oneOf(labelRepository).save(trgLabel);
		}});
		SUT.submitInput();
		expect.that(trgLabel.getTodoByTitle(todo3Title)).isNotNull();
	}
	
	@Specification
	void shouldDoNothingIfAddTodoAlreadyIn() {
		setInited();
		
		setNullSelected();
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue(todo2Title));
		}});
		SUT.submitInput();
		
		setSelected();
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue(todo1Title));
		}});
		SUT.submitInput();
		
		setSelected();
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue(todo2Title));
		}});
		SUT.submitInput();
	}
	
	@Specification
	void shouldDoNothingIfAddEmptyOrSpacedTodo() {
		setInited();
		setNullSelected();
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue(""));
		}});
		SUT.submitInput();
		
		setNullSelected();
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue("      "));
		}});
		SUT.submitInput();
	}

	@Specification
	void shouldReplaceTodoAndListItemAndSaveLabelIfSelected() {
		setInited();
		setSelected();
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue(todo3Title));
			oneOf(todoSettingsActivity).replaceInWorkingList(todo3Title);
			oneOf(labelRepository).save(trgLabel);
		}});
		SUT.submitInput();
		expect.that(trgLabel.getTodoByTitle(todo2Title)).isNull();
		expect.that(trgLabel.getTodoByTitle(todo3Title)).isNotNull();
	}
	
	@Specification
	void shouldRemoveTodoAndListItemAndSaveLabelIfSelectedWithEmptyInput() {
		setInited();
		setSelected();
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getInputString(); will(returnValue(""));
			oneOf(todoSettingsActivity).removeFromWorkingList();
			oneOf(labelRepository).save(trgLabel);
		}});
		SUT.submitInput();
		expect.that(trgLabel.getTodoByTitle(todo2Title)).isNull();
	}
	
	void setInited() {
		trgLabel.inviteTodo(todo1Title);
		trgLabel.inviteTodo(todo2Title);
		expect.that(new Expectations() {{
			Map<String, Boolean> chkMap = new HashMap<String, Boolean>();
			chkMap.put(todo1Title, false);
			chkMap.put(todo2Title, false);
			oneOf(todoSettingsActivity).setWorkingTitle(with(equal(trgLabelTitle)));
			oneOf(todoSettingsActivity).setWorkingList(with(equal(chkMap)));
		}});
		SUT.initializeWith(todoSettingsActivity);
	}
	
	void setNullSelected() {
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getSelected(); will(returnValue(null));
		}});
	}
	
	void setSelected() {
		expect.that(new Expectations() {{
			oneOf(todoSettingsActivity).getSelected(); will(returnValue(todo2Title));
		}});
	}
}
